﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Model;
using Bll;
using Common;
using Web.Extension;
using Web.Util;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authorization;
using System.IO;
using System.Data;
using Web.Redis;
using StackExchange.Redis;
using System.Collections;
using Web.Controllers;
using Quartz;
using Common.Util;
using Web.Security;
using Microsoft.Extensions.Logging;
using Web.Filter;

namespace Web.Teach.Controllers
{
    [Route("api/teach/[controller]/[action]")]
    [ApiController]
    [Authorize("teacher")]
    [IdentityModelActionFilter]
    public class ClockController : MyBaseController
    {

        public IClasssBll classsBll { get; set; }
        public  ICourseBll courseBll { get; set; }
        public IStudentBll bll { get; set; }
        public IClockBll clockBll { get; set; }
        public ITimeTableBll timeTableBll { get; set; }
        private readonly IWebHostEnvironment webHostEnvironment;
        public ClockController(IWebHostEnvironment hostingEnvironment)
        {
            this.webHostEnvironment = hostingEnvironment;
        }
        // GET: api/List/Clock
        [HttpGet]
        public Result List([FromQuery] Dictionary<string, string> where)
        {
            var CourseSn = where["CourseSn"];
            where.Remove("TeacherId");
            where.Remove("CourseSn");
            //根据课程编号查询考勤 数据
            var courese=  courseBll.SelectOne(o=>o.Sn==CourseSn);
            where.Add("CourseId", courese.Id+"");
            return Result.Success("succeed").SetData(clockBll.Query(where));
        }
        /// <summary>
        ///  教师发起学生签到。实时签到（远程签到）
        /// </summary>
        /// <param name="classid">班级id</param>
        /// <param name="courseid">课程id</param>
        /// <param name="answer">签到问题答案</param>
        /// <param name="expire">签到时长</param>
        /// <param name="holdexpire">签到信息保留时间，默认签到时长（默认 60）+120秒，后签到信息自动删除</param>
        /// <returns></returns>
        [HttpPost()]
        public Result JitClock(string classid, string courseid, string answer, int expire = 60, int holdexpire = 120)
        {
            return PublishClock(bll, typeof(SaveClockInfoJob), Clock.ClockType.midway, classid, MyUser.Id.ToString(), courseid, answer, expire, holdexpire);
        }
        /// <summary>
        /// 获取已签到学生列表
        /// </summary>
        /// <param name="classid"></param>
        /// <returns></returns>
        [HttpGet()]
        public Result ClockList(string classid)
        {
            //缓存学生信息
            MyRedisHelper rd = MyRedisHelper.Instance();
            //所有待签到的学生集合
            rd.SetSysCustomKey("clock_stu_all");
            //获取所有用户名集合 
            List<string> keys = rd.HashKeys<string>(classid.ToString());
            rd.SetSysCustomKey("clock_stu");//切换到已签到的学生集合
            //签到列表
            var ss = new ArrayList();
            List<ElementScore<string>> clockss = rd.SortedSetRangeByRankWithScores<string>(classid.ToString());//升序
            //切换到所有人列表                                                                                                  //所有待签到的学生集合
            rd.SetSysCustomKey("clock_stu_all");
            foreach (ElementScore<string> c in clockss)
            {
                if (c.Element == "#0#") continue;
                ss.Add(new { username = c.Element, realname = rd.HashGet<StudentInfo>(classid, c.Element).Realname, time = DateTime.FromOADate(c.Score).ToString("HH:mm:ss") });
            }
            return Result.Success("查询成功").SetData(new { total = keys.Count, items = ss });//total总人数
        }
        /// <summary>
        /// 查询未签到列表
        /// </summary>
        /// <param name="classid">班级id</param>
        /// <returns>new { total= 总人数,items=未签到列表对象{username,realname }}</returns>
        [HttpGet()]
        public Result UnClockList(string classid)
        {
            //缓存学生信息
            MyRedisHelper rd = MyRedisHelper.Instance();
            //所有待签到的学生集合
            rd.SetSysCustomKey("clock_stu_all");
            //获取所有用户名集合
            List<string> keys = rd.HashKeys<string>(classid.ToString());
            rd.SetSysCustomKey("clock_stu");//切换到已签到的学生集合
            //未签到列表
            var ss = new ArrayList();
            //循环
            foreach (var k in keys)
            {
                if (!rd.SortedSetContains<string>(classid, k))
                { //如果不包含表示未签到
                    rd.SetSysCustomKey("clock_stu_all");
                    ss.Add(new { username = k, realname = rd.HashGet<StudentInfo>(classid, k).Realname });
                    rd.SetSysCustomKey("clock_stu");
                }
            }
            return Result.Success("查询成功").SetData(new { total = keys.Count, items = ss });//total总人数
        }
        /// <summary>
        /// 发布签到
        /// </summary>
        /// <param name="bll"></param>
        /// <param name="type"></param>
        /// <param name="clockType"></param>
        /// <param name="classid"></param>
        /// <param name="courseid"></param>
        /// <param name="answer"></param>
        /// <param name="expire"></param>
        /// <param name="holdexpire"></param>
        /// <param name="teacherid"></param>
        /// <returns></returns>
        public static Result PublishClock(IStudentBll bll, Type type, Clock.ClockType clockType, string classid, string teacherid, string courseid, string answer, int expire = 60, int holdexpire = 120)
        {
            //缓存学生信息
            //设置对应班级所有待签到学生列表
            MyRedisHelper rd = MyRedisHelper.Instance();
            rd.SetSysCustomKey("clock_stu_all");//所有待签到的学生集合
            if (!rd.KeyExists(classid.ToString()))
            {
                var stus = bll.SelectAll(o => o.ClasssId == int.Parse(classid));
                foreach (var s in stus)
                {
                    //rd.HashSet(classid.ToString(), s.Username, new { s.Realname });
                    rd.HashSet<StudentInfo>(classid.ToString(), s.Username, new StudentInfo() { Id = s.Id, Realname = s.Realname });
                }
            }
            //设置已签到列表 
            rd.SetSysCustomKey("clock_stu");//已签到的学生集合 
            bool has = rd.SortedSetContains(classid, "#0#");//签到信息保存时间
            if (has)
            {
                NLogHelper.logger.Info("发起签到失败,请等待当前签到结束,或者" + holdexpire + "秒后再发起签到");
                Console.WriteLine("发起签到失败,请等待当前签到结束,或者" + holdexpire + "秒后再发起签到");
                return Result.Error("发起签到失败,请等待当前签到结束,或者" + holdexpire + "秒后再发起签到");
            }
            NLogHelper.logger.Info($"发布签到:班级{classid}，课程{courseid}");
            Console.WriteLine($"发布签到:班级{classid}，课程{courseid}");
            rd.SortedSetAdd(classid, "#0#", DateTime.Now.ToOADate());//已签到集合默认不然没法设置有效时间
            rd.KeyExpire(classid, TimeSpan.FromSeconds(expire + holdexpire));//设置签到信息保留时间
            rd.StringSet(classid + "expire", expire, TimeSpan.FromSeconds(expire));//签到时长
            //签到答案 start
            //RedisValue class_answer = rd.StringGet(classid + "answer");//签到答案 同一时间在合班上课 一个教师对应多个班，签到答案只有一个
            //if (class_answer.IsNullOrEmpty)//供班级学生获取
            //{
            //    rd.StringSet(classid + "answer", answer, TimeSpan.FromSeconds(expire));//签到答案
            //}           
            string teacher_answer = rd.StringGet(teacherid + "_teacher_answer");//签到答案，供教师获取然后发给学生
            if (string.IsNullOrEmpty(teacher_answer))//同一时间在合班上课 一个教师对应多个班，签到答案只有一个
            {
                rd.StringSet(teacherid + "_teacher_answer", answer, TimeSpan.FromSeconds(expire));//签到答案，供教师获取然后发给学生
                rd.StringSet(classid + "answer", answer, TimeSpan.FromSeconds(expire));//签到答案
            }
            else
            {
                rd.StringSet(classid + "answer", teacher_answer, TimeSpan.FromSeconds(expire));//签到答案
            }
            //签到答案 end
            rd.StringSet(classid + "teacher", teacherid, TimeSpan.FromSeconds(expire));//课程班级教师，供学生获取当前签到课程对应教师id
            //添加定时任务 在签到结束后将数据持久化到数据库
            Dictionary<string, object> data = new Dictionary<string, object>();
            data.Add("classid", classid);
            data.Add("courseid", courseid);
            data.Add("answer", answer);
            data.Add("from_time", DateTime.Now);
            data.Add("clockType", clockType);
            //QuartzHelper.AddAfter(typeof(SaveClockInfoJob), new JobKey(classid, "classJitClock"), expire + 1, data);
            QuartzHelper.AddAfter(type, new JobKey(classid, "classClock"), expire + 1, data);
            return Result.Success("发起签到成功");
        }
    }
    class StudentInfo
    {
        public int Id { get; set; }
        public string Realname { get; set; }
    }
    #region 保存签到信息
    /// <summary>
    /// 依赖注入参考https://www.cnblogs.com/lonelyxmas/p/11788930.html
    /// https://blog.csdn.net/mzl87/article/details/88046815
    /// </summary>

    public class SaveClockInfoJob : IJob
    {
        public IClockBll clockBll { get; set; }
        public IClockLogBll clockLogBll { get; set; }
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
            {
                var classid = Convert.ToInt32(context.JobDetail.JobDataMap.GetString("classid"));
                var courseid = Convert.ToInt32(context.JobDetail.JobDataMap.GetString("courseid"));
                var answer = context.JobDetail.JobDataMap.GetString("answer");
                var from_time = context.JobDetail.JobDataMap.GetDateTime("from_time");
                var clockType = (Clock.ClockType)context.JobDetail.JobDataMap.Get("clockType");
                //缓存学生信息
                MyRedisHelper rd = MyRedisHelper.Instance();
                //所有待签到的学生集合
                rd.SetSysCustomKey("clock_stu_all");
                //获取所有用户名集合
                List<string> keys = rd.HashKeys<string>(classid.ToString());
                rd.SetSysCustomKey("clock_stu");//切换到已签到的学生集合    
                var len = rd.SortedSetLength(classid.ToString()) - 1;
                //签到记录
                Clock clock = new Clock() { Name = clockType.GetText(), Type = clockType, Total = keys.Count, Clocked_num = (int)len, From_time = from_time, To_time = DateTime.Now };
                if (classid != 0)
                {
                    clock.ClasssId = classid;
                }
                if (courseid != 0)
                {
                    clock.CourseId = courseid;
                }
                clockBll.Add(clock);
                //循环
                //签到详细
                List<ClockLog> logs = new List<ClockLog>();
                foreach (var k in keys)
                {

                    rd.SetSysCustomKey("clock_stu_all");
                    var s = rd.HashGet<StudentInfo>(classid.ToString(), k);
                    ClockLog log = new ClockLog() { Clock = clock, StudentId = s.Id, Status = ClockLog.ClockStatus.normal };
                    //切换到已签到学生
                    rd.SetSysCustomKey("clock_stu");
                    if (!rd.SortedSetContains<string>(classid.ToString(), k))
                    { //如果不包含表示未签到
                        log.Status = ClockLog.ClockStatus.absence;//缺席                                                                 
                    }
                    logs.Add(log);
                }
                clockLogBll.Add(logs);
                //LogUtil.Debug("执行MyJob");
            });
        }
    }
    #endregion
  
}
